feat(tests/screencast): add Python/Playwright screencast pipeline + hello_world demo scenario#3042
Open
mettta wants to merge 39 commits into
Open
feat(tests/screencast): add Python/Playwright screencast pipeline + hello_world demo scenario#3042mettta wants to merge 39 commits into
mettta wants to merge 39 commits into
Conversation
… videos are never committed
tests/screencast/ was a raw copy of the demo-video generator from the strictdoc-project.github.io (Hugo) repository. This is the first step of moving that generator into the StrictDoc repo itself (see developer/tasks/20260704_screencast/task.md). Removed as part of this cleanup: - demo.js, package.json, package-lock.json, node_modules/: the JS/Playwright pipeline is being rewritten in Python (Playwright has a full Python API), so StrictDoc gains no new Node.js/npm dependency. - run_demo.py: only orchestrated the now-removed `npm run demo` step. - fixtures/strictdoc-demo-project/.local/: personal working notes with another machine's absolute paths and stray duplicate .sdoc files, not part of the actual demo fixture. - __pycache__/, .DS_Store, and the generated fixtures/.../output/ cache: build artifacts, not source. Still present, to be replaced in a later stage: run_server.py and strictdoc_server.py, which currently start StrictDoc by shelling out to `tox` against a sibling repo checkout — an assumption that only made sense outside the StrictDoc repo. These will be replaced by reusing tests/end2end/server.py::SDocTestServer. No functional change to StrictDoc itself; tests/screencast is not yet wired into any invoke task.
Adds the `playwright` Python package to requirements.check.txt, alongside seleniumbase, since it is installed and used through the same tox `check` environment as the end2end test suite. This is the dependency needed for the tests/screencast video-generation pipeline being rewritten in Python (see developer/tasks/20260704_screencast/task.md). The pipeline code itself and the one-time `playwright install chromium` browser-binary setup step will follow in later stages of that task.
Replaces the ad-hoc strictdoc_server.py (which shelled out to `tox -e py310-development` against a sibling `../strictdoc` checkout — an assumption that only made sense when this generator lived in the strictdoc-project.github.io repo) with the already-hardened tests/end2end/server.py::SDocTestServer, used as-is via its context-manager interface. Adds tests/screencast/fixture.py with the shared fixture-project and port constants (a separate RECORD_SERVER_PORT is reserved for the upcoming video-recording mode, so a manual dev server can stay open while a scenario re-records). run_server.py is rewritten to start/stop the demo server through SDocTestServer directly — no tox subprocess, no sibling-checkout assumption, no STRICTDOC_ROOT/STRICTDOC_TOX/pyenv-version env vars. Manually verified: the server starts against the demo fixture, serves HTTP 200, and shuts down cleanly on exit.
…st tests Replaces the JSON-step scene definitions in the removed demo.js with two ordinary pytest test cases, following the tests/end2end/screens/*/test_case.py convention: each screencast scenario is now a real regression check, not just a replayed sequence of UI actions. - strictdoc_ui/test_case.py: browse a StrictDoc document, switch to the table view, and assert on document title, viewtype menu, and the resulting table view state. - ide_typing_to_table/test_case.py: the IDE-style fake-typing scene (demo.html) followed by the same table-view flow. - scenarios/conftest.py: a local `page` pytest fixture (headless Chromium via playwright.sync_api directly — no pytest-playwright plugin needed for this scope). - scenarios/typing.py: the fake-typing effect ported from demo.js's typeText() (appends to textContent; not real keyboard input). Note: tests/end2end's Screen_*/component Page Object helpers are tied to SeleniumBase (BaseCase, By.XPATH) and cannot be reused as-is by Playwright code. The same underlying selectors (#viewtype_handler, [data-viewtype_link="table"], body[data-viewtype], .header__document_title) are used directly instead, verified against the actually rendered demo fixture pages. Both scenarios currently run without recording video; recording mode is added in a follow-up stage. Manually verified: both tests pass under the `check` tox environment (playwright + chromium installed) against the demo fixture server.
…st tests Replaces the JSON-step scene definitions in the removed demo.js with two ordinary pytest test cases, following the tests/end2end/screens/*/test_case.py convention: each screencast scenario is now a real regression check, not just a replayed sequence of UI actions. - strictdoc_ui/test_case.py: browse a StrictDoc document, switch to the table view, and assert on document title, viewtype menu, and the resulting table view state. - ide_typing_to_table/test_case.py: the IDE-style fake-typing scene (demo.html) followed by the same table-view flow. - scenarios/conftest.py: a local `page` pytest fixture (headless Chromium via playwright.sync_api directly — no pytest-playwright plugin needed for this scope). - scenarios/typing.py: the fake-typing effect ported from demo.js's typeText() (appends to textContent; not real keyboard input). tests/end2end's Screen_*/component Page Object helpers are tied to SeleniumBase (BaseCase, By.XPATH) and cannot be called from Playwright code. Instead of inlining locators per test, this adds new Playwright-native helpers under tests/screencast/helpers/ (Screen, ViewTypeSelector), mirroring the existing helpers' names, selectors, and responsibilities — meant for reuse across this suite now and as a starting point for a wider Playwright migration later, per SDG guidance to avoid one-off duplication once more than one call site exists. Both scenarios currently run without recording video; recording mode is added in a follow-up stage. Manually verified: both tests pass under the `check` tox environment (playwright + chromium installed) against the demo fixture server.
Makes each screencast scenario dual-purpose, as designed in developer/tasks/20260704_screencast/task.md: by default it's a fast pass/fail regression check with no video output; with --strictdoc-record-video, the same test also captures and saves a .webm. - fixture.py: add OUTPUT_DIR (tests/screencast/output/). - scenarios/conftest.py: add the --strictdoc-record-video pytest option; the `page` fixture enables Playwright's record_video_dir only when the flag is set, and on context close saves the recording as output/<scenario-dir-name>.webm (e.g. strictdoc_ui.webm), removing Playwright's temporary video file afterwards. Removed the two leftover .webm files from the old JS pipeline (strictdoc-ui.webm, ide-to-table.webm) — different naming scheme, no longer produced by this generator. Manually verified: scenarios pass both without the flag (no video written) and with it (both named .webm files produced, no stray temp files left in output/).
Adds `invoke test-screencast` (alias `tsc`) in tasks.py, following the same tox `check`-environment convention as test_end2end/test_unit_server (junit-xml under build/test_reports/, dedicated pytest cache dir). Options: - --focus: pytest -k filter, same as other test-* tasks. - --record-video: forwards --strictdoc-record-video to pytest, so the same invocation both runs the regression checks and (re)generates the .webm videos into tests/screencast/output/. Kept separate from invoke test-end2end per developer/tasks/20260704_screencast/task.md: screencast runs are slower/produce binary artifacts, and the scenarios always run headless (no headed/--headless flag needed, unlike SeleniumBase-based end2end tests). Manually verified: `invoke test-screencast` and `invoke test-screencast --record-video` both pass and behave as expected (2 passed; the latter produces strictdoc_ui.webm and ide_typing_to_table.webm in tests/screencast/output/).
…line Replaces the README carried over from strictdoc-project.github.io (which documented `npm install --prefix demo`, STRICTDOC_ROOT/STRICTDOC_TOX env vars, and a sibling-checkout setup) with docs matching the pipeline as it now exists in this repo: directory layout, the one-time `playwright install chromium` setup step, `invoke test-screencast` (with --focus/--record-video), the manual dev server via run_server.py, and a short guide for adding new scenarios using the helpers/ Page Objects. A failing scenario means its video can no longer be trusted, not that it should be re-recorded automatically: investigate first (it may be a product bug or an intentional UI change the scenario doesn't reflect yet), and re-record once the scenario is fixed or updated and passing again. Also fixes fixtures/strictdoc-demo-project/README.md, which still referred to a `demo/` directory that no longer exists. Manually verified: `invoke test-screencast` passes (2 passed) as a final end-to-end sanity check of the whole rewritten pipeline.
…plate - Rewrites WHAT/WHY/HOW to match developer/tasks/task.template.md - Removes narrative that didn't belong in a task specification
…ctions run_server.py imports project dependencies (psutil, watchdog via strictdoc itself) that only exist in this project's tox environments, not in a bare system `python3`. Running it directly with `python3 tests/screencast/run_server.py` fails with `ModuleNotFoundError: No module named 'watchdog'`. Adds `invoke screencast-server` (alias `scs`), following the same pattern as the existing `invoke server` task: runs run_server.py through the `check` tox environment (the one with psutil/playwright/etc., matching `invoke test-screencast`), so it has the dependencies it needs. Updates tests/screencast/README.md to document `invoke screencast-server` instead of the bare `python3` invocation. Manually verified: `invoke screencast-server` starts the demo server and serves HTTP 200 against the fixture project; `invoke test-screencast` still passes end-to-end after these changes.
…ults DEV_SERVER_PORT was 5111 — StrictDoc's own default project server port (ProjectConfigDefault.DEFAULT_SERVER_PORT), the same one `invoke server` uses. Running `invoke screencast-server` and `invoke server` at the same time (or leaving one running) collides on that port; this is what caused `invoke server`'s "Address already in use" failure. RECORD_SERVER_PORT (5112) had the same problem one level down: it's tests/end2end's SDocTestServer default fallback port, used by any end2end test that doesn't pass an explicit port. Moves both ports to 5301/5302, clear of StrictDoc's own default (5111) and the end2end port range (5112-5212). Updates tests/screencast/README.md's port references to match. Manually verified: `invoke test-screencast` (2 passed, server on 5302) and `invoke screencast-server` (serves HTTP 200 on 5301) both work on the new ports, and leave 5111 untouched.
…-screencast
Adds .github/workflows/screencast-tests.yml, separate from
end2end-tests.yml: sets up the `check` tox environment, installs
Playwright's Chromium binary (not covered by pip install), then runs
`invoke test-screencast`. Without this, the WHY in
developer/tasks/20260704_screencast/task.md ("ties video freshness
directly to the same CI/dev signal already used for UI regressions") was
aspirational rather than true — nothing ran these scenarios automatically.
Also fixes lint issues in tests/screencast/run_server.py surfaced by
`invoke lint`: dropped the unused shebang (the script is only ever invoked
via `python tests/screencast/run_server.py`, never executed directly),
switched `List[...]` to `list[...]`, and added `# noqa: T201` to its
prints, matching the rest of the codebase's convention for intentional
console output.
Manually verified: each workflow step run locally in sequence (tox
--notest, pip_install_strictdoc_deps.py, playwright install chromium,
invoke test-screencast) succeeds; `ruff check tests/screencast/` is clean.
- `invoke screencast-server` gains `--focus=<scenario>` to manually preview scenarios that don't use the shared fixture project (like hello_world, which generates its own project on demand into the gitignored build/screencast_manual/<scenario>/ and reuses it across restarts).
- New `hello_world` screencast scenario: runs a real `strictdoc new`, types the command and its actual stdout into a terminal-style HTML scene, then drives a live server through creating a document and a requirement via the web UI (tests/screencast/scenarios/hello_world/). - New Playwright helpers ported from the e2e SeleniumBase suite for the add-document and add-requirement flows (tests/screencast/helpers/).
Adds Pointer (fake mouse cursor + click-target highlight, since Playwright renders no real cursor) and pause() pacing helper; reworks the hello_world scenario to skip document creation, add a Requirement to the existing High-Level Requirements doc instead, and close with an editor-style scene revealing the real appended .sdoc lines.
Moves the cursor/highlight CSS out of the inline JS template string in pointer.py into pointer.css, embedded via json.dumps() instead of repr() so the CSS can safely contain quotes/backslashes without breaking the generated JS.
…DocLexer Reuses StrictDoc's own Pygments lexer and pygments.css (same ones used to highlight `.. code:: strictdoc` blocks in the docs) to render the .sdoc source in the editor scene, instead of plain unhighlighted text.
…syntax highlighting in README Adds coverage in tests/screencast/README.md for the helpers table, video resolution (VIEWPORT_SIZE), pacing/pause knobs, the fake cursor/highlight mechanism (pointer.py/pointer.css), editing terminal/editor scene styles, and the real StrictDocLexer-based syntax highlighting — none of which was documented after the recent Pointer/hello_world work.
…dd --edit and a startup banner `invoke screencast-server` now defaults to a fresh, disposable copy of the scenario's project (nothing persists, the shared fixture is never touched); pass --edit to serve the real, persistent files instead. Replaces the plain startup print with a boxed banner (matching StrictDoc's own server banner style) showing scenario/mode/URL, with display-width-aware padding so wide characters don't misalign the frame.
…6/UP037/UP045) Replaces typing.List/Dict/Tuple/Optional/Union with list/dict/tuple/X | None/X | Y in manual_scenarios.py, helpers/editor_scene.py, and helpers/pointer.py (UP006/UP045, no safe autofix available); also picks up ruff --fix's automatic removal of a now-redundant quoted forward-reference in helpers/node.py's Requirement.with_node return type (UP037), safe to auto-fix since from __future__ import annotations is already in effect there.
…st pipeline Add web-optimized video export to the screencast pipeline Recorded tests/screencast/output/*.webm files are VP8, sized for editing, not for embedding on the product website. Add `invoke screencast-optimize-video` (alias `scov`), which re-encodes each recording into a muted tests/screencast/output/web/<scenario>.webm (VP9) + <scenario>.mp4 (H.264, for Safari/older browsers) pair, capped at 1280px wide without upscaling narrower recordings. Resolves ffmpeg via PATH with a clear error if it's missing.
…nstead of adding one Switches the scenario to open Low-Level Requirements and add a Rationale to the existing LLR-1 (was: creating a new HLR-2 requirement). editor_scene.reveal_change() now diff-inserts changed lines at their real position in the file instead of only appending at the end. Terminal/demo scenes get proper flex+overflow scrolling so typed/appended text auto-scrolls into view.
…ve path in `strictdoc new` output Pointer's fake cursor starts hidden (opacity:0), appearing only on first move/click — scenes with no clicks (terminal/editor) no longer show it frozen in a corner. run_strictdoc_new now passes a relative path + cwd so the command's own printed "Location"/"cd" output stays short instead of leaking pytest's absolute tmp_path.
…video Navigates to the terminal scene before running the real `strictdoc new` subprocess — video recording starts as soon as the browser context exists, so running the subprocess first left about:blank white on screen for the first second of the recording.
…orld Adds Node.do_click_parent_relation()/do_click_child_relation() (StrictDoc renders these as plain a.requirement__link-parent/child, no data-testid) and a new scene: LLR-1 → its Parent (cross-document navigation to HLR-1) → back via the Child relation, before editing.
… narrow viewports min-width: 0 override for the flexbox min-width:auto default, which was making width: 99% ineffective at narrow widths (flexbug).
…eal fix Commented out, not deleted — this margin exists so the last anchor in a document can scroll fully into view, but also causes an unwanted jump-to-bottom when following any fragment link on a short page. Disabling here rather than fixing properly (a real fix needs the margin to apply conditionally, e.g. via a JS-toggled class, not pure CSS).
…nale Waits for the just-opened edit form's height to stabilize (it keeps growing briefly right after appearing) before scrolling .main to the bottom — otherwise the scroll undershoots against still-growing content.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
invoke test-screencast) that also (re)generates its.webmvia--record-video, backed by a real liveSDocTestServerinstance and a small Playwright Page Object layer (tests/screencast/helpers/).hello_worldscenario: a realstrictdoc newrun (shown in a terminal-style scene) → browsing the generated project in the web UI → following a Requirement's Parent/Child relation links across documents → editing an existing Requirement to add a Rationale → an editor-style scene revealing the real resulting.sdocdiff, syntax-highlighted with StrictDoc's ownStrictDocLexer.Pointer(a fake cursor + click-target highlight, since Playwright renders no real cursor), pacing helpers for deliberate pauses, terminal/editor/IDE-typing HTML playgrounds, and web-optimized video export.invoke screencast-serverfor manually previewing a scenario in a real browser — defaults to a disposable, read-only copy of the project (nothing persists, the shared fixture is never touched);--editopts into the real, persistent files when intentionally curating them.README.mddocumenting the whole mechanism: commands, pacing/cursor knobs, scene-editing, the read-only/--editmanual server, syntax highlighting.